/*
 @file main.c
 @author Paul Hubbard
 @date 5-Feb-2008
 @brief User-level 'driver' for the Omrom HJ-720ITC USB-connected pedometer. Me want data on OSX!
 @note code starting from excellent Apple base at http://developer.apple.com/hardwaredrivers/customusbdrivers.html
 @note Project page at http://code.google.com/p/omron-osx-driver/
 */

#include <stdio.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/hid/IOHIDKeys.h>
#include <CoreFoundation/CoreFoundation.h>

#include <sys/cdefs.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFPlugInCOM.h>
#include <IOKit/IOTypes.h>
#include <IOKit/IOReturn.h>
#include <IOKit/hid/IOHIDKeys.h>

//! @note this is required for example - Interface122 is obsolete it seems. Deprecated?
#include <IOKit/hid/IOHIDLibObsolete.h>

// Structure for USB report from device - buffer may be wrong size!
struct reader 
{
	io_object_t ioObject;
	IOHIDDeviceInterface122 **interface;
	int gotdata;
	unsigned char buffer[64];
};

//! Global variables
SInt32 score;
IOCFPlugInInterface **plugInInterface;
CFRunLoopSourceRef eventSource;
mach_port_t port;
struct reader *r;

//! Defines for this pedometer, extracted from USB Prober.app
const int ourVendor = 0x0590;   //! Omron Corporation
const int ourDevice = 0x0028;   // 'HHX-CABLE-USB1'

// Called when Omron is found, frees device when done
int workerRoutine(const io_object_t hidDevice)
{
    IOReturn retval;
    IOHIDReportType reportType;
    uint32_t reportID;
    void *reportBuffer = NULL;
    uint32_t *reportBufferSize = 0;
    uint32_t timeoutMS = 5000;
    
    printf("\nOmron found!\n");

    /* 
    Do we use interrupt endpoint or report descriptor 1? Assume report and go from there based on USB prober
    Check IOHIDDeviceInterface setReport to send queries, assume challenge/response for now. Gotta start 
    somewhere.
    
    See listing 10 on http://developer.apple.com/hardwaredrivers/customusbdrivers.html
     */
    retval = *getReport( hidDevice, 
    
    IOObjectRelease(hidDevice);
    return(0);
}

// Main routine
int main(int argc, char *argv[]) 
{
	IOReturn result = kIOReturnSuccess;
	io_iterator_t hidObjectIterator = 0;
	io_object_t hidDevice = IO_OBJECT_NULL;
	CFMutableDictionaryRef hidMatchDictionary = 0;
    CFMutableDictionaryRef hidProperties = 0;
    boolean_t  omFound = FALSE;
    boolean_t  debug = FALSE;
    
    
    hidMatchDictionary = IOServiceMatching(kIOHIDDeviceKey);
    result = IOServiceGetMatchingServices(kIOMasterPortDefault,
                                          hidMatchDictionary,
                                          &hidObjectIterator);
    if ((result != kIOReturnSuccess) || (hidObjectIterator == 0)) 
    {
        printf("Can't obtain an IO iterator\n");
        exit(1);
    }
    
    if(argc > 1)
    {
        printf("\nDebug enabled!\n");
        debug = TRUE;
    }
    
    // Iterate over HID devices attached to the system
    while ((hidDevice = IOIteratorNext(hidObjectIterator))) 
    {
        hidProperties = 0;
        int vendor = 0, product = 0;
        result = IORegistryEntryCreateCFProperties(hidDevice, &hidProperties,
                                                   kCFAllocatorDefault, kNilOptions);
        if ((result == KERN_SUCCESS) && hidProperties) 
        {
            CFNumberRef vendorRef, productRef;
            
            vendorRef = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDVendorIDKey));
            productRef = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDProductIDKey));
            if (vendorRef) 
            {
                CFNumberGetValue(vendorRef, kCFNumberIntType, &vendor);	   
                CFRelease(vendorRef);
            }
            if (productRef) 
            {
                CFNumberGetValue(productRef, kCFNumberIntType, &product);
                CFRelease(productRef);
            }

            // DDT
            if(debug)
                printf("Got a device: vendor %04x, product %04x\n", vendor, product);

            // Is it our boy?
            if((vendor == ourVendor) && (product == ourDevice))
            {
                // Worker routine frees device
                workerRoutine(hidDevice);
                omFound = TRUE;
                break;
            }
        }
        IOObjectRelease(hidDevice);
    }
    // After while loop, release iterator
	IOObjectRelease(hidObjectIterator);
    
    if(!omFound)
    {
        printf("\nOmron not attached, exiting.\n");
        return(1);
    }
    
	return 0;
}


